#include "codeeditor.h"
#include <QPaintEvent>
#include <QTextBlock>
#include <QPainter>
#include <QKeyEvent>
#include <QTextDocument>
#include <QRegularExpression>
#include <QTextBlockUserData>
#include <QAbstractTextDocumentLayout>
#include <QWheelEvent>

CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
{
    lineNumberArea = new LineNumberArea(this);
    highlighter = new SyntaxHighlighter(document());

    // 初始化自动缩进设置
    autoIndentEnabled = true;
    tabSpaces = 4;

    // 初始化括号配对设置
    parenthesesMatchingEnabled = true;

    connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth);
    connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea);
    connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine);
    connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::matchParentheses);

    updateLineNumberAreaWidth(0);
    highlightCurrentLine();
}

void CodeEditor::wheelEvent(QWheelEvent *event)
{
    if (event->modifiers() & Qt::ControlModifier) {
        if (event->angleDelta().y() > 0) {
            emit zoomInRequested();
        } else {
            emit zoomOutRequested();
        }
        event->accept();
    } else {
        QPlainTextEdit::wheelEvent(event);
    }
}

void CodeEditor::keyPressEvent(QKeyEvent *e)
{
    // 处理 Tab 键 - 转换为 4 个空格
    if (e->key() == Qt::Key_Tab && !e->isAutoRepeat()) {
        QTextCursor cursor = textCursor();
        if (cursor.hasSelection()) {
            // 如果有选中文本，缩进选中的多行
            int start = cursor.selectionStart();
            int end = cursor.selectionEnd();

            cursor.setPosition(start);
            int startBlock = cursor.blockNumber();

            cursor.setPosition(end, QTextCursor::KeepAnchor);
            int endBlock = cursor.blockNumber();

            cursor.beginEditBlock();

            for (int i = startBlock; i <= endBlock; ++i) {
                QTextBlock block = document()->findBlockByNumber(i);
                cursor.setPosition(block.position());
                cursor.insertText(QString(tabSpaces, ' '));
            }

            cursor.endEditBlock();
        } else {
            // 没有选中文本，插入 4 个空格
            insertPlainText(QString(tabSpaces, ' '));
        }
        return;
    }

    // 处理回车键 - 自动缩进
    if (e->key() == Qt::Key_Return && !e->isAutoRepeat()) {
        if (autoIndentEnabled) {
            autoIndent();
            return;
        }
    }

    // 处理括号自动配对
    if (parenthesesMatchingEnabled) {
        QChar charToInsert;
        bool shouldPair = false;
        QString pairChar;

        switch (e->key()) {
        case Qt::Key_ParenLeft:
            charToInsert = '(';
            pairChar = ")";
            shouldPair = true;
            break;
        case Qt::Key_BraceLeft:
            charToInsert = '{';
            pairChar = "}";
            shouldPair = true;
            break;
        case Qt::Key_BracketLeft:
            charToInsert = '[';
            pairChar = "]";
            shouldPair = true;
            break;
        case Qt::Key_QuoteDbl:
            charToInsert = '"';
            pairChar = "\"";
            shouldPair = true;
            break;
        case Qt::Key_Apostrophe:
            charToInsert = '\'';
            pairChar = "'";
            shouldPair = true;
            break;
        default:
            break;
        }

        if (shouldPair) {
            QTextCursor cursor = textCursor();

            // 检查是否有选中文本
            if (cursor.hasSelection()) {
                QString selectedText = cursor.selectedText();
                cursor.insertText(charToInsert + selectedText + pairChar);

                // 将光标移动到选中文本之后
                cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, pairChar.length());
                setTextCursor(cursor);
            } else {
                // 没有选中文本，插入配对的括号并将光标放在中间
                cursor.insertText(charToInsert + pairChar);
                cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1);
                setTextCursor(cursor);
            }
            return;
        }
    }

    // 处理退格键 - 智能删除配对的括号
    if (e->key() == Qt::Key_Backspace && !e->isAutoRepeat()) {
        QTextCursor cursor = textCursor();
        if (!cursor.hasSelection()) {
            cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
            QString text = cursor.selectedText();

            // 检查常见的配对字符
            if ((text == "(" && document()->characterAt(cursor.position()) == ')') ||
                (text == "{" && document()->characterAt(cursor.position()) == '}') ||
                (text == "[" && document()->characterAt(cursor.position()) == ']') ||
                (text == "\"" && document()->characterAt(cursor.position()) == '"') ||
                (text == "'" && document()->characterAt(cursor.position()) == '\'')) {

                cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);
                cursor.removeSelectedText();
                return;
            }
        }
    }

    // 默认处理其他按键
    QPlainTextEdit::keyPressEvent(e);
}

void CodeEditor::autoIndent()
{
    QTextCursor cursor = textCursor();
    int position = cursor.position();
    Q_UNUSED(position)

    // 获取当前块（行）
    QTextBlock currentBlock = cursor.block();
    QString currentLine = currentBlock.text();

    // 查找前一个非空行
    QTextBlock prevBlock = currentBlock.previous();
    while (prevBlock.isValid() && prevBlock.text().trimmed().isEmpty()) {
        prevBlock = prevBlock.previous();
    }

    QString prevLine = prevBlock.isValid() ? prevBlock.text() : "";

    // 计算缩进
    QString indent;
    for (int i = 0; i < prevLine.length(); ++i) {
        if (prevLine[i].isSpace()) {
            indent += prevLine[i];
        } else {
            break;
        }
    }

    // 如果上一行以 { 结尾，或是典型控制语句，增加一级缩进
    QString trimmedPrevLine = prevLine.trimmed();
    if (!trimmedPrevLine.isEmpty() &&
        (trimmedPrevLine.endsWith('{') ||
         trimmedPrevLine.endsWith('(') ||
         trimmedPrevLine.startsWith("if") ||
         trimmedPrevLine.startsWith("for") ||
         trimmedPrevLine.startsWith("while") ||
         trimmedPrevLine.startsWith("else"))) {
        indent += QString(tabSpaces, ' ');
    }

    // 插入新行和缩进
    cursor.beginEditBlock();
    cursor.insertText("\n" + indent);
    cursor.endEditBlock();

    // 如果当前行以 } 开头，减少一级缩进
    QString trimmedCurrentLine = currentLine.trimmed();
    if (trimmedCurrentLine.startsWith('}') || trimmedCurrentLine.startsWith(')') || trimmedCurrentLine.startsWith(']')) {
        if (indent.length() >= tabSpaces) {
            cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, indent.length());
            cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, tabSpaces);
            cursor.removeSelectedText();
        }
    }
}

void CodeEditor::matchParentheses()
{
    if (!parenthesesMatchingEnabled) return;

    parenthesesSelections.clear();

    QTextCursor cursor = textCursor();
    if (cursor.position() == 0) return;

    // 检查光标左侧的字符
    cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
    QString text = cursor.selectedText();

    QChar openChar, closeChar;
    bool forward = false;

    if (text == "(" || text == "{" || text == "[") {
        openChar = text.at(0);
        closeChar = (text == "(") ? ')' : (text == "{") ? '}' : ']';
        forward = true;
    } else if (text == ")" || text == "}" || text == "]") {
        closeChar = text.at(0);
        openChar = (text == ")") ? '(' : (text == "}") ? '{' : '[';
        forward = false;
    } else {
        return;
    }

    // 查找匹配的括号
    int matchPos = findMatchingParenthesis(cursor, openChar, closeChar);
    if (matchPos != -1) {
        QTextEdit::ExtraSelection selection;
        selection.format.setBackground(QColor(0, 255, 0, 100)); // 浅绿色高亮
        selection.format.setProperty(QTextFormat::FullWidthSelection, false);

        // 高亮当前括号
        selection.cursor = cursor;
        parenthesesSelections.append(selection);

        // 高亮匹配的括号
        QTextCursor matchCursor = cursor;
        matchCursor.setPosition(matchPos);
        matchCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);
        selection.cursor = matchCursor;
        parenthesesSelections.append(selection);
    } else {
        // 没有找到匹配的括号，用红色高亮
        QTextEdit::ExtraSelection selection;
        selection.format.setBackground(QColor(255, 0, 0, 100)); // 浅红色高亮
        selection.cursor = cursor;
        parenthesesSelections.append(selection);
    }

    // 应用高亮
    QList<QTextEdit::ExtraSelection> allSelections = extraSelections();
    allSelections.append(parenthesesSelections);
    setExtraSelections(allSelections);
}

int CodeEditor::findMatchingParenthesis(QTextCursor cursor, QChar open, QChar close)
{
    int direction = (open == '(' || open == '{' || open == '[') ? 1 : -1;
    int depth = 1;
    int pos = cursor.position();

    while (true) {
        pos += direction;
        if (pos < 0 || pos >= document()->characterCount()) break;

        QChar ch = document()->characterAt(pos);
        if (ch == open) {
            depth += direction;
        } else if (ch == close) {
            depth -= direction;
        }

        if (depth == 0) {
            return pos;
        }
    }

    return -1; // 没有找到匹配的括号
}

void CodeEditor::insertPlainTextWithIndent(const QString &text)
{
    QTextCursor cursor = textCursor();

    // 获取当前缩进
    QTextBlock currentBlock = cursor.block();
    QString currentLine = currentBlock.text();
    QString indent;
    for (int i = 0; i < currentLine.length(); ++i) {
        if (currentLine[i].isSpace()) {
            indent += currentLine[i];
        } else {
            break;
        }
    }

    // 插入文本并保持缩进
    cursor.insertText(indent + text);
}

void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
    QPainter painter(lineNumberArea);
    painter.fillRect(event->rect(), Qt::lightGray);

    QTextBlock block = firstVisibleBlock();
    int blockNumber = block.blockNumber();
    int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());
    int bottom = top + qRound(blockBoundingRect(block).height());

    const int numberLeft = kFoldIndicatorWidth; // 留出折叠符区域
    const int numberWidth = lineNumberArea->width() - numberLeft;

    while (block.isValid() && top <= event->rect().bottom()) {
        if (block.isVisible() && bottom >= event->rect().top()) {
            // 行号
            QString number = QString::number(blockNumber + 1);
            painter.setPen(Qt::black);
            painter.drawText(numberLeft, top, numberWidth, fontMetrics().height(),
                             Qt::AlignRight, number);

            // 折叠指示器
            int endBN = -1;
            bool foldable = isFoldableBlock(block, &endBN);
            if (foldable) {
                // 读取（或默认）折叠状态
                BlockData *bd = static_cast<BlockData*>(block.userData());
                bool folded = bd ? bd->folded : false;

                // 画一个小三角形：向下=展开，向右=折叠
                int size = qMax(8, fontMetrics().height() - 6);
                int cx = 4 + size / 2; // 左侧居中
                int cy = top + (qRound(blockBoundingRect(block).height()) - size) / 2 + size / 2;

                QPolygon poly;
                if (folded) {
                    // 向右
                    poly << QPoint(cx - size/3, cy - size/2)
                         << QPoint(cx - size/3, cy + size/2)
                         << QPoint(cx + size/3, cy);
                } else {
                    // 向下
                    poly << QPoint(cx - size/2, cy - size/3)
                         << QPoint(cx + size/2, cy - size/3)
                         << QPoint(cx,           cy + size/3);
                }
                painter.setBrush(Qt::darkGray);
                painter.setPen(Qt::NoPen);
                painter.drawPolygon(poly);
            }

            // 添加断点标记
            if (breakpoints.contains(blockNumber + 1)) {
                painter.setPen(Qt::red);
                painter.drawEllipse(4, top + fontMetrics().height() / 2 - 3, 6, 6);
            }
        }

        block = block.next();
        top = bottom;
        bottom = top + qRound(blockBoundingRect(block).height());
        ++blockNumber;
    }
}

void CodeEditor::setBreakpoints(const QList<int> &bp)
{
    breakpoints = bp;
    update();
    emit breakpointsChanged(bp);
}

int CodeEditor::lineNumberAreaWidth()
{
    int digits = 1;
    int max = qMax(1, blockCount());
    while (max >= 10) {
        max /= 10;
        ++digits;
    }

    // 兼容不同 Qt 版本
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
    int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
#else
    int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
#endif
    // 预留折叠指示区域
    space += kFoldIndicatorWidth + 4;
    return space;
}

void CodeEditor::resizeEvent(QResizeEvent *event)
{
    QPlainTextEdit::resizeEvent(event);

    QRect cr = contentsRect();
    lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}

void CodeEditor::updateLineNumberAreaWidth(int newBlockCount)
{
    Q_UNUSED(newBlockCount)
    setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}

void CodeEditor::highlightCurrentLine()
{
    QList<QTextEdit::ExtraSelection> extraSelections;

    if (!isReadOnly()) {
        QTextEdit::ExtraSelection selection;

        QColor lineColor = QColor(Qt::yellow).lighter(160);

        selection.format.setBackground(lineColor);
        selection.format.setProperty(QTextFormat::FullWidthSelection, true);
        selection.cursor = textCursor();
        selection.cursor.clearSelection();
        extraSelections.append(selection);
    }

    // 保留括号高亮
    extraSelections.append(parenthesesSelections);

    setExtraSelections(extraSelections);
}

void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
{
    if (dy)
        lineNumberArea->scroll(0, dy);
    else
        lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());

    if (rect.contains(viewport()->rect()))
        updateLineNumberAreaWidth(0);
}

// —— 折叠：命中检测 —— //
QTextBlock CodeEditor::blockAtY(int y) const
{
    QTextBlock block = firstVisibleBlock();
    int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());
    int bottom = top + qRound(blockBoundingRect(block).height());

    while (block.isValid()) {
        if (block.isVisible() && y >= top && y < bottom)
            return block;
        block = block.next();
        top = bottom;
        bottom = top + qRound(blockBoundingRect(block).height());
    }
    return QTextBlock();
}



void CodeEditor::lineNumberAreaMousePressEvent(QMouseEvent *event)
{
    if (event->button() != Qt::LeftButton)
        return;

    // 仅当点击在折叠指示区域内时触发
    if (event->pos().x() <= kFoldIndicatorWidth + 4) {
        QTextBlock block = blockAtY(event->pos().y());
        if (block.isValid()) {
            toggleFoldAt(block.blockNumber());
        }
    } else {
        // 点击在行号区域，发送信号
        int line = blockAtY(event->pos().y()).blockNumber() + 1;
        emit lineNumberAreaClicked(line);
    }
}

// —— 折叠：判断与设置 —— //
bool CodeEditor::isFoldableBlock(const QTextBlock &block, int *endBlockNumber) const
{
    if (!block.isValid()) return false;

    const QString text = block.text();

    // 情形 1：大括号块（{ ... }）
    int firstBraceIdx = text.indexOf('{');
    if (firstBraceIdx != -1) {
        int depth = 0;
        bool seenFirstOpen = false;
        QTextBlock b = block;
        while (b.isValid()) {
            const QString s = b.text();
            for (int i = 0; i < s.size(); ++i) {
                const QChar c = s.at(i);
                if (c == '{') { depth++; seenFirstOpen = true; }
                else if (c == '}') { depth--; }
                if (seenFirstOpen && depth == 0) {
                    if (endBlockNumber) *endBlockNumber = b.blockNumber();
                    return b.blockNumber() > block.blockNumber(); // 至少跨 1 行才值得折叠
                }
            }
            b = b.next();
        }
    }

    // 情形 2：多行注释（/* ... */）
    int commentStart = text.indexOf("/*");
    if (commentStart != -1) {
        int sameLineEnd = text.indexOf("*/", commentStart + 2);
        if (sameLineEnd == -1) {
            QTextBlock b = block.next();
            while (b.isValid()) {
                if (b.text().contains("*/")) {
                    if (endBlockNumber) *endBlockNumber = b.blockNumber();
                    return b.blockNumber() > block.blockNumber();
                }
                b = b.next();
            }
        }
    }

    return false;
}

void CodeEditor::setFolded(const QTextBlock &startBlock, bool folded, int endBlockNumber)
{
    // 在起始块上记录折叠信息
    QTextBlock block = startBlock;
    BlockData *bd = static_cast<BlockData*>(block.userData());
    if (!bd) {
        bd = new BlockData();
        block.setUserData(bd);
    }
    bd->folded = folded;
    bd->endBlockNumber = endBlockNumber;

    // 设置被折叠块的可见性（起始块保持可见）
    document()->blockSignals(true);
    QTextBlock b = block.next();
    for (int bn = block.blockNumber() + 1; b.isValid() && bn <= endBlockNumber; ++bn) {
        b.setVisible(!folded);
        b = b.next();
    }
    document()->blockSignals(false);

    // 若光标处于折叠区域内，将其移到起始块末尾
    if (folded) {
        QTextCursor c = textCursor();
        if (c.blockNumber() > block.blockNumber() && c.blockNumber() <= endBlockNumber) {
            QTextCursor nc(block);
            nc.movePosition(QTextCursor::EndOfBlock);
            setTextCursor(nc);
        }
    }

    // 触发重绘与重新布局
    document()->markContentsDirty(startBlock.position(),
                                  document()->characterCount() - startBlock.position());
    viewport()->update();
    updateLineNumberAreaWidth(0);
}

void CodeEditor::toggleFoldAt(int blockNumber)
{
    QTextBlock block = document()->findBlockByNumber(blockNumber);
    if (!block.isValid()) return;

    int endBN = -1;
    if (!isFoldableBlock(block, &endBN)) return;

    BlockData *bd = static_cast<BlockData*>(block.userData());
    bool folded = bd ? !bd->folded : true; // 默认折叠

    setFolded(block, folded, endBN);
}
